package contextlearn

import (
	"context"
	"fmt"
	"sync"
	"time"
)

var wg sync.WaitGroup

//var stop bool = false
var stop chan bool = make(chan bool)

func cpuInfo() {
	defer wg.Done()
	//一直监控
	for {
		//if stop {
		//	break
		//}

		select {
		case <-stop: //这个会一直堵塞
			fmt.Println("退出cpu监控")
			return
		default:
			time.Sleep(time.Second * 2)
			fmt.Println("cpu信息读取完成")
		}

	}

}

func ContextLearnNoContext() {
	//现在启动一个goroutine去监控某台服务器的cpu使用状况
	wg.Add(1)
	go cpuInfo()
	//现在希望可以中断cpu的信息读取
	//1.监控全局变量
	//time.Sleep(time.Second * 6)
	//stop = true
	//2.通过channel实现
	time.Sleep(time.Second * 6)
	stop <- true

	//close(stop)
	wg.Wait() //是要等goroutine退出后才执行

	fmt.Println("信息监控完成")

}

func cpuInfo2(ctx context.Context) {
	defer wg.Done()

	//go memInfo2(ctx)
	ctx2, _ := context.WithCancel(ctx)
	go memInfo2(ctx2)

	for {
		select {
		case <-ctx.Done():
			fmt.Println("监控cpu退出")
			return
		default:
			time.Sleep(time.Second * 2)
			fmt.Println("cpu信息读取完成")
		}
	}

}

func memInfo2(ctx context.Context) {
	defer wg.Done()
	for {
		select {
		case <-ctx.Done():
			fmt.Println("监控mem退出")
			return
		default:
			time.Sleep(time.Second)
			fmt.Println("mem信息读取完成")
		}
	}

}
func ContextLearnWithContext() {
	//3.go1.7+提供了context机制
	//使用context实现，在主协程中，取消子协程的任务
	//需要用context.Background()生成一个父context
	ctx, cancel := context.WithCancel(context.Background())
	wg.Add(1)
	go cpuInfo2(ctx)
	//wg.Add(1)
	//go memInfo2(ctx)
	time.Sleep(time.Second * 6)
	cancel()
	//父context取消后，基于该context的子context都会取消
	//context在web中非常常用，grpc每个接口都会传递context;gin的http接口也会有context
	wg.Wait()
	fmt.Println("信息监控完成")
}

func ContextLearnTimeout() {
	//context.WithCancel()
	//context.WithDeadline()
	//context.WithTimeout()
	//context.WithValue()
	ctx, _ := context.WithTimeout(context.Background(), time.Second*5)
	wg.Add(1)
	go memInfo2(ctx)
	//time.Sleep(time.Second * 3)
	//cancel() //也可以手动触发
	wg.Wait()
	fmt.Println("信息监控完成")
}
